package com.wujunshen.mongodb.utils;

import com.mongodb.client.result.DeleteResult;
import com.wujunshen.mongodb.page.Page;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
import lombok.AllArgsConstructor;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.mongodb.core.query.Update;

/**
 * @author frank woo(吴峻申) <br>
 * email:<a href="mailto:frank_wjs@hotmail.com">frank_wjs@hotmail.com</a> <br>
 * @date 2020/2/7 5:33 下午 <br>
 */
@AllArgsConstructor
public class MongoUtils {
    /**
     * spring mongodb　集成操作类
     */
    private final MongoTemplate mongoTemplate;
    
    /**
     * 获取所有集合名
     *
     * @return 集合名列表
     */
    public List<String> getCollectionNames() {
        return new ArrayList<>(mongoTemplate.getCollectionNames());
    }
    
    /**
     * 通过条件查询实体(集合)
     *
     * @param query 查询条件
     * @return 实体列表
     */
    public <T> List<T> find(Query query, Class<T> tClass) {
        return mongoTemplate.find(query, tClass);
    }
    
    /**
     * 查询所有实体对象
     *
     * @return 实体列表
     */
    public <T> List<T> findAll(Class<T> tClass) {
        return mongoTemplate.findAll(tClass);
    }
    
    /**
     * 通过一定的条件查询一个实体
     *
     * @param query 查询条件
     * @return 实体类
     */
    public <T> T findOne(Query query, Class<T> tClass) {
        return mongoTemplate.findOne(query, tClass);
    }
    
    /**
     * 通过条件查询更新数据
     *
     * @param query  查询条件
     * @param update 更新条件类
     */
    public <T> T update(Query query, Update update, Class<T> tClass) {
        return mongoTemplate.findAndModify(query, update, tClass);
    }
    
    /**
     * 保存一个对象到mongodb
     *
     * @param entity 实体类
     * @return 实体类
     */
    public <T> T save(T entity) {
        mongoTemplate.insert(entity);
        return entity;
    }
    
    /**
     * 保存所有对象
     *
     * @param list 对象列表
     * @param <T>  实体类型
     * @return 实体列表
     */
    public <T> List<T> saveAll(List<T> list) {
        return list.stream().map(this::save).collect(Collectors.toList());
    }
    
    /**
     * 删除某个实体
     *
     * @param entity 实体对象
     * @param <T>    实体类型
     * @return 删除是否成功 true成功 false失败
     */
    public <T> boolean deleteOne(T entity) {
        DeleteResult result = mongoTemplate.remove(entity);
        if (result.wasAcknowledged()) {
            return (result.getDeletedCount() > 0);
        }
        return false;
    }
    
    /**
     * 删除所有对象
     *
     * @param query  搜索条件
     * @param tClass 对象类型
     * @param <T>    实体类型
     * @return 删除是否成功 true成功 false失败
     */
    public <T> boolean deleteAll(Query query, Class<T> tClass) {
        DeleteResult result = mongoTemplate.remove(query, tClass);
        if (result.wasAcknowledged()) {
            return result.getDeletedCount() > 0;
        }
        return false;
    }
    
    /**
     * 根据ID删除对象
     *
     * @param id     ID
     * @param tClass 对象类型
     * @param <T>    实体类型
     * @return 删除是否成功 true成功 false失败
     */
    public <T> boolean deleteById(String id, Class<T> tClass) {
        return deleteOne(this.findById(id, tClass));
    }
    
    /**
     * 通过ID获取记录
     *
     * @param id ID
     * @return 实体类
     */
    public <T> T findById(String id, Class<T> tClass) {
        return mongoTemplate.findById(id, tClass);
    }
    
    /**
     * 通过ID获取记录,并且指定了集合名(表的意思)
     *
     * @param id             ID
     * @param collectionName 集合名
     * @return 实体类
     */
    public <T> T findById(String id, Class<T> tClass, String collectionName) {
        return mongoTemplate.findById(id, tClass, collectionName);
    }
    
    /**
     * 分页查询
     *
     * @param page  分页类
     * @param query 查询条件
     * @return 分页类
     */
    public <T> Page<T> findPage(Page<T> page, Query query, Class<T> tClass) {
        long count = this.count(query, tClass);
        page.setTotalCount(count);
        int pageNo = page.getPageNo();
        int pageSize = page.getPageSize();
        query.skip((pageNo - 1) * pageSize).limit(pageSize);
        List<T> rows = this.find(query, tClass);
        page.setList(rows);
        return page;
    }
    
    /**
     * 求数据总和
     *
     * @param query 查询条件
     * @return 数据条数
     */
    public <T> long count(Query query, Class<T> tClass) {
        return mongoTemplate.count(query, tClass);
    }
    
    /**
     * 删除集合
     *
     * @param collectionName 集合名
     */
    public void drop(String collectionName) {
        mongoTemplate.dropCollection(collectionName);
    }
}
